using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.IO;
using System.Linq;
using UnityEngine;

namespace AGame.TabOrm
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T">需要解析的；类</typeparam>
    /// <typeparam name="TKey">主键类型，多主键并且主键之间类型不同，可以填objetc</typeparam>
    public class TabRepository<T, TKey> : IRepository<T, TKey>, IEnumerable<T>
    {
        private readonly Type _type;
        private readonly Table _tableMate;
        private BaseField[] _fields;
        private Dictionary<int, T> _oneKeyDict;

        private Dictionary<int, int>[] _keyCountDict;
        private readonly List<T> _objList = new List<T>();
        public TabOrmObjConvert ObjConvert = TabOrmObjConvert.CommonConvert;

        private Dictionary<int, int> _idToStringCacheIndexDict;
        private string[] _stringCacheArray;

        private Dictionary<int, List<T>> _keyListDict;

        private Action<T> _init;
        private Action<T> _saveBefore;
        private Action<T> _saveAfter;

        public int Count => _objList.Count;

        public event Action OnRefresh;

        public TabRepository()
        {
            _type = typeof(T);
            _tableMate = _type.GetCustomAttribute<Table>();
        }

        public void BuildRepository()
        {
            if (_tableMate == null)
            {
                throw new Exception("该类必须有Table注解" + _type.Name);
            }

            var content = GetFileContent();
            if (string.IsNullOrEmpty(content))
            {
                throw new Exception("这是一个不能用的表 : " + _tableMate.Path);
            }

            var startDataLine = _tableMate.HasDesc ? 3 : 2;
            var lines = content.Replace("\r", "").Split('\n');
            lines = lines.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
            if (lines.Length < startDataLine)
            {
                throw new Exception("这是一个行数不够不能用的表" + _tableMate.Path);
            }

            var column = lines[0].Split('\t');
            var tabType = lines[1].Split('\t');

            if (column.Any(string.IsNullOrWhiteSpace))
            {
                throw new Exception("这是一个表头存在空列的表" + _tableMate.Path);
            }

            string[] desc = null;
            if (_tableMate.HasDesc)
            {
                desc = lines[2].Split('\t');
                if (desc.Length < column.Length)
                {
                    throw new Exception("这是一个描述不够不能用的表" + _tableMate.Path);
                }
            }

            if (tabType.Length < column.Length)
            {
                throw new Exception("这是一个类型数量不够不能用的表" + _tableMate.Path);
            }

            var keyNum = _tableMate.KeyNum;
            if (column.Length < keyNum)
            {
                throw new Exception("这是一个键不够不能用的表" + _tableMate.Path);
            }

            _fields = new BaseField[column.Length];

            int index;

            //解析所有字段
            foreach (var fieldInfo in _type.GetFields())
            {
                var field = fieldInfo.GetCustomAttribute<TabField>();
                var name = field == null ? fieldInfo.Name :
                    string.IsNullOrEmpty(field.Name) ? fieldInfo.Name :
                    field.Name;
                if ((index = Array.IndexOf(column, name)) < 0)
                {
                    continue;
                }

                Func<string, object> strToObj = null;
                Func<object, string> objToStr = null;
                if (field != null)
                {
                    objToStr = field.GetObjToStrFunc(_type, fieldInfo.FieldType);
                    strToObj = field.GetStrToObjFunc(_type, fieldInfo.FieldType);
                }

                _fields[index] = new TabFieldField(fieldInfo)
                {
                    ObjConvertToStr = objToStr ?? ObjConvert.GetObjToStringFunc(fieldInfo.FieldType),
                    StrConvertToObj = strToObj ?? ObjConvert.GetStringToObjFunc(fieldInfo.FieldType),
                    Desc = _tableMate.HasDesc ? desc?[index] : string.Empty,
                    TabType = _tableMate.HasDesc ? tabType[index] : string.Empty,
                    Name = name
                };
            }

            foreach (var propertyInfo in _type.GetProperties())
            {
                var field = propertyInfo.GetCustomAttribute<TabField>();
                var name = field == null ? propertyInfo.Name :
                    string.IsNullOrEmpty(field.Name) ? propertyInfo.Name :
                    field.Name;
                if ((index = Array.IndexOf(column, name)) < 0)
                {
                    continue;
                }

                Func<string, object> strToObj = null;
                Func<object, string> objToStr = null;
                if (field != null)
                {
                    objToStr = field.GetObjToStrFunc(_type, propertyInfo.PropertyType);
                    strToObj = field.GetStrToObjFunc(_type, propertyInfo.PropertyType);
                }

                _fields[index] = new TabPropertyField(propertyInfo)
                {
                    ObjConvertToStr = objToStr ?? ObjConvert.GetObjToStringFunc(propertyInfo.PropertyType),
                    StrConvertToObj = strToObj ?? ObjConvert.GetStringToObjFunc(propertyInfo.PropertyType),
                    Desc = _tableMate.HasDesc ? desc?[index] : string.Empty,
                    TabType = _tableMate.HasDesc ? tabType[index] : string.Empty,
                    Name = name
                };
            }

            //初始化方法,判断是否有初始化方法
            foreach (var methodInfo in _type.GetMethods())
            {
                if (methodInfo.GetCustomAttribute<TabInitialize>() != null)
                {
                    _init = obj => { methodInfo.Invoke(obj, Array.Empty<object>()); };
                }

                if (methodInfo.GetCustomAttribute<TabSaveBefore>() != null)
                {
                    _saveBefore = obj => { methodInfo.Invoke(obj, Array.Empty<object>()); };
                }

                if (methodInfo.GetCustomAttribute<TabSaveAfter>() != null)
                {
                    _saveAfter = obj => { methodInfo.Invoke(obj, Array.Empty<object>()); };
                }
            }

            //指定初始容量
            if (keyNum > 0)
            {
                _oneKeyDict = new Dictionary<int, T>(lines.Length);
                _keyCountDict = new Dictionary<int, int>[keyNum];
                for (var i = 0; i < _keyCountDict.Length; i++)
                {
                    _keyCountDict[i] = new Dictionary<int, int>();
                }

                if (_tableMate.BuildList > 0 && _tableMate.BuildList < keyNum)
                {
                    _keyListDict = new Dictionary<int, List<T>>();
                }
            }

            // 延时初始化
            if (_tableMate.IsDelayRead())
            {
                _stringCacheArray = new string[lines.Length - startDataLine];
                for (var i = startDataLine; i < lines.Length; i++)
                {
                    _stringCacheArray[i - startDataLine] = lines[i];
                }

                while (_objList.Count < _stringCacheArray.Length)
                {
                    _objList.Add(default);
                }

                if (keyNum <= 0)
                {
                    return;
                }

                _idToStringCacheIndexDict = new Dictionary<int, int>();

                //如果有键索引，就创建键对行索引
                //辅助生成键的对象
                var idArray = new TKey[keyNum];
                for (var i = 0; i < _stringCacheArray.Length; i++)
                {
                    var data = _stringCacheArray[i].Split(new[] {'\t'}, keyNum + 1);
                    var count = Math.Min(keyNum, data.Length);
                    Array.Clear(idArray, 0, idArray.Length);
                    for (var j = 0; j < count; j++)
                    {
                        idArray[j] = (TKey) _fields[j]?.StringToObject(data[j]);
                    }

                    //考虑到，如果要是有一行少了列数，那么这一行就可能会引用上一行的某列作为id
                    var hashCode = CalcHashCode(idArray);
                    _idToStringCacheIndexDict[hashCode] = i;

                    for (var j = 0; j < keyNum; j++)
                    {
                        var hash = idArray[j].GetHashCode();
                        if (!_keyCountDict[j].ContainsKey(hash))
                        {
                            _keyCountDict[j][hash] = 1;
                        }
                        else
                        {
                            _keyCountDict[j][hash]++;
                        }
                    }
                }
            }
            else
            {
                //数据读入并初始化所有对象
                for (var i = startDataLine; i < lines.Length; i++)
                {
                    Add(CreateInstanceByString(lines[i]));
                }
            }
        }

        private T CreateInstanceByString(string str)
        {
            var instance = Activator.CreateInstance(_type);
            var data = str.Split('\t');
            var count = Math.Min(_fields.Length, data.Length);
            for (var j = 0; j < count; j++)
            {
                _fields[j]?.Set(instance, data[j]);
            }

            return (T) instance;
        }

        public void RefreshTab()
        {
            UnInit();
            BuildRepository();
            OnRefresh?.Invoke();
        }

        /// <summary>
        /// 加进来的实例会检测ID是否与当前已有的ID冲突，如果添加失败，一般是已有该ID，但是不排除多键的哈希冲突
        /// 如果已有ID对象就会添加失败，如果没有则会用该对象的ID作为索引
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Add(T obj)
        {
            if (_tableMate.KeyNum > 0)
            {
                var hashCode = CalcHashCode(obj);
                if (ContainsKey(hashCode))
                {
                    var stringBuilder = new StringBuilder();
                    stringBuilder.AppendLine("哈希冲突了");
                    stringBuilder.AppendLine("Path:" + _tableMate.Path);
                    for (var i = 0; i < _tableMate.KeyNum; i++)
                    {
                        var key = (TKey) _fields[i]?.GetValue(obj);
                        stringBuilder.AppendLine($"Key{i}:{key}    HashCode:{key?.GetHashCode()}");
                    }

                    if (_oneKeyDict.TryGetValue(hashCode, out var oldObj))
                    {
                        stringBuilder.AppendLine("---------");
                        for (var i = 0; i < _tableMate.KeyNum; i++)
                        {
                            var key = (TKey) _fields[i]?.GetValue(oldObj);
                            stringBuilder.AppendLine($"Key{i}:{key}    HashCode:{key?.GetHashCode()}");
                        }
                    }

                    Debug.LogError(stringBuilder);
                    return false;
                }

                _oneKeyDict[hashCode] = obj;
                for (var i = 0; i < _tableMate.KeyNum; i++)
                {
                    var hash = _fields[i].GetValue(obj).GetHashCode();
                    if (!_keyCountDict[i].ContainsKey(hash))
                    {
                        _keyCountDict[i][hash] = 1;
                    }
                    else
                    {
                        _keyCountDict[i][hash]++;
                    }
                }

                InsertBuildList(obj);
            }

            _objList.Add(obj);
            _init?.Invoke(obj);
            (obj as ITableInitialize)?.Init();
            return true;
        }

        /// <summary>
        /// 考虑到，如果一个对象希望被替换，即，有一个新数据希望可以替换掉同键的原数据时，可以使用
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="needInit"></param>
        /// <returns></returns>
        public bool Set(T obj, bool needInit = false)
        {
            if (_tableMate.KeyNum == 0)
            {
                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("不存在键");
                stringBuilder.AppendLine("Path:" + _tableMate.Path);
                Debug.LogError(stringBuilder);
                return false;
            }

            var hashCode = CalcHashCode(obj);
            if (!TryGetValue(hashCode, out var srcData))
            {
                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("不存在原数据");
                stringBuilder.AppendLine("Path:" + _tableMate.Path);
                for (var i = 0; i < _tableMate.KeyNum; i++)
                {
                    var key = (TKey) _fields[i]?.GetValue(obj);
                    stringBuilder.AppendLine($"Key{i}:{key}    HashCode:{key?.GetHashCode()}");
                }

                Debug.LogError(stringBuilder);
                return false;
            }

            int indexOf;
            if (srcData == null)
            {
                indexOf = _idToStringCacheIndexDict[hashCode];
                _idToStringCacheIndexDict.Remove(hashCode);
                _stringCacheArray[indexOf] = null;
            }
            else
            {
                indexOf = _objList.IndexOf(srcData);
                if (indexOf < 0)
                {
                    Debug.LogError("不存在索引");
                    return false;
                }
            }

            _oneKeyDict[hashCode] = obj;
            _objList[indexOf] = obj;
            if (needInit)
            {
                _init?.Invoke(obj);
                (obj as ITableInitialize)?.Init();
            }

            return true;
        }

        private bool ContainsKey(int hashCode)
        {
            if (_tableMate.KeyNum == 0)
            {
                return false;
            }

            return _oneKeyDict.ContainsKey(hashCode) || (_idToStringCacheIndexDict?.ContainsKey(hashCode) ?? false);
        }

        private bool TryGetValue(int hashCode, out T data)
        {
            data = default;
            if (_tableMate.KeyNum == 0)
            {
                return false;
            }

            return _oneKeyDict.TryGetValue(hashCode, out data) ||
                   (_idToStringCacheIndexDict?.ContainsKey(hashCode) ?? false);
        }

        public bool Remove(T obj)
        {
            var indexOf = _objList.IndexOf(obj);
            return indexOf >= 0 && RemoveAt(indexOf);
        }

        public bool RemoveAt(int index)
        {
            var obj = _objList[index];
            if (_tableMate.KeyNum > 0)
            {
                var hashCode = CalcHashCode(obj);
                if (!_oneKeyDict.ContainsKey(hashCode))
                {
                    Debug.LogError("无法取得的哈希");
                    return false;
                }

                _oneKeyDict.Remove(hashCode);
                for (var i = 0; i < _tableMate.KeyNum; i++)
                {
                    var hash = _fields[i].GetValue(obj).GetHashCode();
                    _keyCountDict[i][hash]--;
                }

                RemoveBuildList(obj);
            }

            _objList.RemoveAt(index);
            return true;
        }

        public bool ContainsKey(params TKey[] id)
        {
            if (id.Length > _tableMate.KeyNum)
            {
                return false;
            }

            if (id.Length == _tableMate.KeyNum)
            {
                var calcHashCode = CalcHashCode(id);
                return ContainsKey(calcHashCode);
            }

            for (var i = 0; i < id.Length; i++)
            {
                var hashCode = id[i].GetHashCode();
                if (!_keyCountDict[i].TryGetValue(hashCode, out var count) || count <= 0)
                {
                    return false;
                }
            }

            return true;
        }

        public List<T> GetDataList(params TKey[] id)
        {
            if (_stringCacheArray != null)
            {
                CreateAllData();
            }

            if (id.Length == 0)
            {
                return _objList;
            }

            if (_keyListDict == null)
            {
                return null;
            }

            var calcHashCode = CalcHashCode(id);
            return _keyListDict.TryGetValue(calcHashCode, out var list) ? list : null;
        }

        public IEnumerable<TKey[]> Keys()
        {
            if (_tableMate.KeyNum == 0)
            {
                yield break;
            }

            foreach (var data in this)
            {
                yield return GetDataId(data);
            }
        }

        public IEnumerable<TKey> FirstKeys()
        {
            if (_tableMate.KeyNum == 0)
            {
                return Array.Empty<TKey>();
            }

            return Keys().Where(keys => keys.Length > 0)
                .Select(keys => keys[0])
                .Distinct();
        }

        private void CreateAllData()
        {
            if (_stringCacheArray == null)
            {
                return;
            }

            for (var i = 0; i < _stringCacheArray.Length; i++)
            {
                ConvertStringToInstance(i);
            }

            _idToStringCacheIndexDict = null;
            _stringCacheArray = null;
        }

#if UNITY_EDITOR
        public void WriteTab()
        {
            var strFileName =
                $"{(_tableMate.ConfigPath ? Application.streamingAssetsPath : Application.dataPath)}/{_tableMate.Path}";
            if (!File.Exists(strFileName))
            {
                return;
            }

            for (var i = 0; i < _fields.Length; i++)
            {
                if (_fields[i] == null)
                {
                    Debug.LogError($"写入失败! {strFileName}文件 第{i + 1}列为空");
                    return;
                }
            }

            var builder = new StringBuilder();
            try
            {
                var objStringList = new string[_objList.Count][];
                var keyNum = _tableMate.KeyNum;
                for (var i = 0; i < objStringList.Length; i++)
                {
                    var obj = _objList[i];
                    if (obj == null)
                    {
                        var str = _stringCacheArray[i];
                        objStringList[i] = str.Split('\t');
                        var stringArray = objStringList[i];
                        if (stringArray.Length != _fields.Length)
                        {
                            objStringList[i] = new string[_fields.Length];
                            Array.Copy(stringArray, objStringList[i], _fields.Length);
                        }

                        continue;
                    }

                    _saveBefore?.Invoke(obj);
                    (obj as ITableSaveBefore)?.SaveBefore();
                    var strings = new string[_fields.Length];
                    for (var j = 0; j < _fields.Length; j++)
                    {
                        strings[j] = _fields[j].Get(obj);
                    }

                    _saveAfter?.Invoke(obj);
                    (obj as ITableSaveAfter)?.SaveAfter();
                    objStringList[i] = strings;
                }

                IEnumerable<string[]> objList = objStringList;
                if (_tableMate.SaveSort && keyNum > 0)
                {
                    var enumerable = objList.OrderBy(obj => _fields[0].StringToObject(obj[0]));
                    for (var i = 1; i < keyNum; i++)
                    {
                        var index = i;
                        enumerable = enumerable.ThenBy(obj => _fields[index].StringToObject(obj[index]));
                    }

                    objList = enumerable;
                }

                foreach (var field in _fields)
                {
                    builder.Append(field.Name).Append('\t');
                }

                builder.Remove(builder.Length - 1, 1);
                builder.AppendLine();
                foreach (var field in _fields)
                {
                    builder.Append(field.TabType).Append('\t');
                }

                builder.Remove(builder.Length - 1, 1);
                builder.AppendLine();

                foreach (var field in _fields)
                {
                    builder.Append(field.Desc).Append('\t');
                }

                builder.Remove(builder.Length - 1, 1);
                builder.AppendLine();

                foreach (var strArray in objList)
                {
                    if (strArray.Length == 0)
                    {
                        continue;
                    }

                    builder.Append(strArray[0]);
                    for (var i = 1; i < strArray.Length; i++)
                    {
                        builder.Append('\t').Append(strArray[i] ?? "");
                    }

                    builder.AppendLine();
                }
            }
            catch (Exception e)
            {
                Debug.LogError($"写入失败! {strFileName} {e}");
                return;
            }

            var fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write, FileShare.Read);
            var file = new StreamWriter(fs, Encoding.GetEncoding(_tableMate.Encode));
            try
            {
                file.Write(builder);
                file.Flush();
                file.Close();
                Debug.Log($"已写入文件{strFileName}");
            }
            catch (Exception e)
            {
                Debug.LogError($"写入失败! {strFileName} {e}");
                file.Close();
            }

            ;
        }
#endif

        public T GetDataById(params TKey[] id)
        {
            return TryGetDataById(out var data, id) ? data : default;
        }

        public bool TryGetDataById(out T res, params TKey[] id)
        {
            if (_oneKeyDict == null)
            {
                res = default;
                return false;
            }

            var hashCode = CalcHashCode(id);
            if (_oneKeyDict.TryGetValue(hashCode, out res))
            {
                return true;
            }

            if (_idToStringCacheIndexDict == null || !_idToStringCacheIndexDict.TryGetValue(hashCode, out var index))
            {
                res = default;
                return false;
            }

            ConvertStringToInstance(index);
            return _oneKeyDict.TryGetValue(hashCode, out res);
        }

        private T ConvertStringToInstance(int index)
        {
            if (_stringCacheArray == null || _stringCacheArray.Length <= index)
            {
                return default;
            }

            var str = _stringCacheArray[index];
            if (string.IsNullOrEmpty(str))
            {
                return default;
            }

            var obj = CreateInstanceByString(str);
            if (_tableMate.KeyNum > 0)
            {
                var hashCode = CalcHashCode(obj);
                if (_oneKeyDict.ContainsKey(hashCode))
                {
                    Debug.LogError("哈希冲突了");
                    return default;
                }

                _oneKeyDict[hashCode] = obj;
                _idToStringCacheIndexDict.Remove(hashCode);
                InsertBuildList(obj);
            }

            _objList[index] = obj;
            _init?.Invoke(obj);
            (obj as ITableInitialize)?.Init();
            _stringCacheArray[index] = null;
            return obj;
        }

        public T GetDataByIndex(int index)
        {
            var dataByIndex = _objList[index];
            if (_idToStringCacheIndexDict != null && dataByIndex == null)
            {
                dataByIndex = ConvertStringToInstance(index);
            }

            return dataByIndex;
        }

        private void InsertBuildList(T obj)
        {
            if (_keyListDict == null)
            {
                return;
            }

            var key = new TKey[_tableMate.BuildList];
            for (var i = 0; i < _tableMate.BuildList; i++)
            {
                key[i] = (TKey) _fields[i].GetValue(obj);
            }

            var calcHashCode = CalcHashCode(key);
            if (!_keyListDict.TryGetValue(calcHashCode, out var list))
            {
                list = new List<T>();
                _keyListDict[calcHashCode] = list;
            }

            list.Add(obj);
        }

        private void RemoveBuildList(T obj)
        {
            if (_keyListDict == null)
            {
                return;
            }

            var key = new TKey[_tableMate.BuildList];
            for (var i = 0; i < _tableMate.BuildList; i++)
            {
                key[i] = (TKey) _fields[i].GetValue(obj);
            }

            var calcHashCode = CalcHashCode(key);
            if (_keyListDict.TryGetValue(calcHashCode, out var list))
            {
                list.Remove(obj);
            }
            else
            {
                Debug.LogError("获取到的hash无法映射到表上");
            }
        }

        public bool SetDataId(T obj, params TKey[] id)
        {
            var hashCode = CalcHashCode(id);
            if (_oneKeyDict.ContainsKey(hashCode))
            {
                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("哈希冲突了");
                stringBuilder.AppendLine("Path:" + _tableMate.Path);
                for (var i = 0; i < _tableMate.KeyNum; i++)
                {
                    stringBuilder.AppendLine($"Key{i}:{id[i]}    HashCode:{id[i]?.GetHashCode()}");
                }

                if (_oneKeyDict.TryGetValue(hashCode, out var oldObj))
                {
                    stringBuilder.AppendLine("---------");
                    for (var i = 0; i < _tableMate.KeyNum; i++)
                    {
                        var key = (TKey) _fields[i]?.GetValue(oldObj);
                        stringBuilder.AppendLine($"Key{i}:{key}    HashCode:{key?.GetHashCode()}");
                    }
                }

                Debug.LogError(stringBuilder);
                return false;
            }

            var oldHashCode = CalcHashCode(obj);
            if (_oneKeyDict.ContainsKey(oldHashCode))
            {
                if (!Equals(_oneKeyDict[oldHashCode], obj))
                {
                    Debug.Log("有不规范的操作，数据出现问题");
                    return false;
                }

                _oneKeyDict.Remove(oldHashCode);
                _oneKeyDict[hashCode] = obj;

                for (var i = 0; i < _tableMate.KeyNum; i++)
                {
                    var oldHash = _fields[i].GetValue(obj).GetHashCode();
                    var newHash = id[i].GetHashCode();
                    if (oldHash == newHash)
                    {
                        continue;
                    }

                    _keyCountDict[i][oldHash]--;
                    if (!_keyCountDict[i].ContainsKey(newHash))
                    {
                        _keyCountDict[i][newHash] = 1;
                    }
                    else
                    {
                        _keyCountDict[i][newHash]++;
                    }
                }

                RemoveBuildList(obj);
                for (var i = 0; i < id.Length; i++)
                {
                    _fields[i]?.SetValue(obj, id[i]);
                }

                InsertBuildList(obj);
            }
            else
            {
                Debug.Log("储存中没有该对象，不能对该对象的ID进行修改");
                return false;
            }

            return true;
        }

        public TKey[] GetDataId(T obj)
        {
            var tKeys = new TKey[_tableMate.KeyNum];
            if (obj == null)
            {
                return tKeys;
            }

            for (var i = 0; i < _tableMate.KeyNum; i++)
            {
                tKeys[i] = (TKey) _fields[i].GetValue(obj);
            }

            return tKeys;
        }

        private int CalcHashCode(T obj)
        {
            var keys = new TKey[_tableMate.KeyNum];
            for (var i = 0; i < keys.Length; i++)
            {
                keys[i] = (TKey) _fields[i]?.GetValue(obj);
            }

            return CalcHashCode(keys);
        }

        private static int CalcHashCode(IEnumerable<TKey> keys)
        {
            //为什么选1021 ？
            //https://www.it1352.com/69339.html
            //java选用31，一个素数，但是考虑到{2,1}{1,31}哈希冲突了，实际业务之中使用不安全。
            //一般来说，实际业务中双键的情况比较多，三键比较少，考虑第二个键的值一般不会操作1000多，因此这样尽可能避免哈希冲突。
            // hashCode = (hashCode * 397) ^ Stance;
            //如果依旧有冲突的话，可以考虑使用C#的397算法
            return keys?.Aggregate(1, (current, key) => 1021 * current + key.GetHashCode()) ?? 0;
        }

        private string GetFileContent()
        {
            var strFilePath = _tableMate.Path;
            if (string.IsNullOrEmpty(strFilePath))
            {
                return null;
            }

            var isConfigPath = _tableMate.ConfigPath;
            try
            {
                var isGbk = false;
#if UNITY_EDITOR
                var encode = Encoding.GetEncoding(_tableMate.Encode);
                isGbk = isConfigPath || Equals(encode, Encoding.GetEncoding("GBK"));
#else
                if (!File.Exists(FileUtil.HandleLoadPath(strFilePath)))
                {
                    var resourcesPath = _tableMate.ResourcesPath;
                    if (!string.IsNullOrEmpty(resourcesPath))
                    {
                        return Resources.Load<TextAsset>(resourcesPath).text;
                    }
                }
                else
                {
                    isConfigPath = true;
                }
#endif
                //TODO:这里要重新检查读表是否正确
                // if (isConfigPath)
                // {
                //     return Tables.LoadFile(strFilePath, true, isGbk);
                // }

                strFilePath = Application.dataPath + strFilePath;
                if (!File.Exists(strFilePath))
                    return null;

                using (var fs = new FileStream(strFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    using (var reader = new StreamReader(fs, Encoding.GetEncoding(_tableMate.Encode)))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                return null;
            }
        }

        public void UnInit()
        {
            _oneKeyDict?.Clear();
            foreach (var dictionary in _keyCountDict)
            {
                dictionary.Clear();
            }
            if (_type.IsAssignableFrom(typeof(ITableDestroy)))
            {
                foreach (var obj in _objList.Cast<ITableDestroy>())
                {
                    obj.Destroy();
                }
            }
            _objList.Clear();
        }


        public void Destroy()
        {
            UnInit();
            _fields = null;
            _oneKeyDict = null;
            _keyCountDict = null;
            ObjConvert = null;
            _keyListDict = null;
            _init = null;
            _saveBefore = null;
            _saveAfter = null;
            OnRefresh = null;
        }

        public IEnumerator<T> GetEnumerator()
        {
            var count = Count;
            for (var i = 0; i < count; i++)
            {
                var data = GetDataByIndex(i);
                yield return data;
            }
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    internal interface IMemberGetSet
    {
        Type ContentType { get; }

        void SetValue(object obj, object value);

        object GetValue(object obj);
    }

    internal abstract class BaseField : IMemberGetSet
    {
        public string Name;
        public string Desc;
        public string TabType;
        public Func<string, object> StrConvertToObj;
        public Func<object, string> ObjConvertToStr;

        internal void Set(object obj, string value)
        {
            SetValue(obj, StrConvertToObj?.Invoke(value));
        }

        internal string ObjectToString(object obj)
        {
            return ObjConvertToStr?.Invoke(obj);
        }

        internal object StringToObject(string obj)
        {
            return StrConvertToObj?.Invoke(obj);
        }

        internal string Get(object obj)
        {
            return ObjConvertToStr?.Invoke(GetValue(obj));
        }

        public abstract Type ContentType { get; }
        public abstract void SetValue(object obj, object value);

        public abstract object GetValue(object obj);
    }

    internal class TabFieldField : BaseField
    {
        private readonly FieldInfo _fieldInfo;

        internal TabFieldField(FieldInfo fieldInfo)
        {
            _fieldInfo = fieldInfo;
        }

        public override Type ContentType => _fieldInfo.FieldType;

        public override void SetValue(object obj, object value)
        {
            _fieldInfo.SetValue(obj, value);
        }

        public override object GetValue(object obj)
        {
            return _fieldInfo.GetValue(obj);
        }
    }

    internal class TabPropertyField : BaseField
    {
        private readonly PropertyInfo _propertyInfo;

        internal TabPropertyField(PropertyInfo propertyInfo)
        {
            _propertyInfo = propertyInfo;
        }

        public override Type ContentType => _propertyInfo.PropertyType;

        public override void SetValue(object obj, object value)
        {
            _propertyInfo.SetValue(obj, value);
        }

        public override object GetValue(object obj)
        {
            return _propertyInfo.GetValue(obj);
        }
    }

    public interface ITableInitialize
    {
        void Init();
    }

    public interface ITableSaveBefore
    {
        void SaveBefore();
    }

    public interface ITableSaveAfter
    {
        void SaveAfter();
    }

    public interface ITableDestroy
    {
        void Destroy();
    }
}